package email

import (
	"context"
	"encoding/json"
	"fmt"
	"gitee.com/go-caipu-team/go-caipu-plugin-sdk/backend"
	"gitee.com/go-caipu-team/go-caipu-plugin-sdk/backend/datasource"
	"gitee.com/go-caipu-team/go-caipu-plugin-sdk/backend/instancemgmt"
	"go-caipu/pkg/infra/log"
	ds "go-caipu/pkg/services/datasources"
	"go-caipu/pkg/setting"
	"go-caipu/pkg/tsdb/email/models"
	"gorm.io/gorm"
	"os"
	"os/signal"
	"syscall"
	"time"
)

type Service struct {
	im          instancemgmt.InstanceManager
	logger      log.Logger
	cfg         *setting.Cfg
	db          *gorm.DB
	mailService *MailService
}

// ProvideService 提供服务实例
// @param cfg 配置
// @param db 数据库连接 当前使用go-caipu，后续可以独立出来
// @return *Service 服务实例
func ProvideService(cfg *setting.Cfg, db *gorm.DB, pluginDs ds.Service) *Service {

	s := &Service{cfg: cfg, db: db, logger: log.New("tsdb.email")}
	s.im = datasource.NewInstanceManager(s.newInstanceSetting(db))

	s.mailService = Init(db)

	//初使化数据源
	plugin, err := pluginDs.Get(context.Background(), ds.GetDatasourceCommand{Id: "email"})
	if err == nil {
		var secret map[string]string
		_ = json.Unmarshal([]byte(plugin.SecureJsonData), &secret)
		s.mailService.sender = initGoMainSender(plugin.JsonData, secret)
	}

	s.mailService.Start()

	go s.gracefulShutdown()
	return s
}

// 扩展的优雅关闭实现
func (s *Service) gracefulShutdown() {
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

	sig := <-sigChan
	s.logger.Debug("Received signal: %v, initiating graceful shutdown...", sig)

	// 关闭所有服务
	s.mailService.Stop()
	s.logger.Debug("All services stopped, shutdown complete")
}

func (s *Service) newInstanceSetting(db *gorm.DB) datasource.InstanceFactoryFunc {
	return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
		// 实现具体的实例创建逻辑
		var datasource models.DataSourceInfo
		err := json.Unmarshal(settings.JSONData, &datasource)
		if err != nil {
			panic("Can not unmarshal plugin email JSON data")
		}
		datasource.Password = settings.DecryptedSecureJSONData["password"]
		sender := initGoMainSender(settings.JSONData, settings.DecryptedSecureJSONData)

		s.mailService.UpdateService(sender, WithWorkers(3), WithRetryInterval(5*time.Minute), WithMaxRetries(3))

		return s.mailService, nil
	}
}

// initGoMainSender 初使化go-caipu的邮件发送器
func initGoMainSender(data json.RawMessage, secret map[string]string) *GoMailSender {
	var datasource models.DataSourceInfo
	err := json.Unmarshal(data, &datasource)
	if err != nil {
		panic("Can not unmarshal plugin email JSON data")
	}
	datasource.Password = secret["password"]
	return NewGoMailSender(datasource.Host, datasource.Port, datasource.UserName, datasource.Password, datasource.From, datasource.SSl)
}

func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
	return &backend.QueryDataResponse{}, nil
}
func (s *Service) getDSInfo(ctx context.Context, pluginCtx backend.PluginContext) (*MailService, error) {
	i, err := s.im.Get(ctx, pluginCtx)
	if err != nil {
		return nil, err
	}
	instance, ok := i.(*MailService)
	if !ok {
		return nil, fmt.Errorf("failed to cast datsource info")
	}
	return instance, nil
}
func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
	sender.Send(&backend.CallResourceResponse{
		Status: 200,
		Body:   []byte("ok"),
	})
	return nil
}
func (s *Service) Execute(ctx context.Context, req *backend.ExecuteRequest) (*backend.ExecuteResponse, error) {
	im, err := s.getDSInfo(ctx, req.PluginContext)
	if err != nil {
	}
	var models models.Email
	if err := json.Unmarshal(req.JSON, &models); err != nil {
		return nil, err
	}
	err = im.Send(&models)
	return &backend.ExecuteResponse{
		Status: 200,
	}, err
}
func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
	im, err := s.getDSInfo(ctx, req.PluginContext)
	if err != nil {
		return nil, err
	}
	if err2 := im.sender.TestDial(); err2 != nil {
		return &backend.CheckHealthResult{
			Status:  backend.HealthStatusError,
			Message: "failed:" + err2.Error(),
		}, nil
	}
	return &backend.CheckHealthResult{
		Status:  backend.HealthStatusOk,
		Message: "ok",
	}, nil
}
